﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data.Objects.DataClasses;

namespace Zen4SyncModel
{

    internal class Logger : ILogger
    {

        /// <summary>
        /// Returns a new context of the Zen4SyncRepository.
        /// This method is used to create a new context every time that the Model wants to access the data base.
        /// In theory the interest of using this method is that it could be changed easily in a singleton if needed in the future.
        /// In practice using the "using" statement every time we call this method disposes the instance créated. To have a singleton instance,
        /// the "using" statement should be placed only in this method and be deleted from the other methods where this method is called.
        /// </summary>
        /// <returns>Returns a new context of the Zen4SyncRepository</returns>
        public static Zen4SyncRepositoryEntities GetContext()
        {
            return new Zen4SyncRepositoryEntities();
        }

        /// <summary>
        /// Persists information of a ClientSession entity on its IsReadyToStart state.
        /// </summary>
        /// <param name="clientSessionId">Unique identifier of the ClientSession.</param>
        /// <param name="processId">Identifier of the process.</param>
        /// <param name="datetime">Date and time when the ClientSession is ready to start.</param>
        public void ClientSessionIsReadyToStart( Guid clientSessionId, int processId, DateTime dateTime )
        {
            using(Zen4SyncRepositoryEntities z4sEntities = GetContext())
            {
                clientSession clientSession = z4sEntities.clientSession.Where
                    ( cs => cs.clientSession_id == clientSessionId ).SingleOrDefault();

                if ( clientSession != null )
                {
                    clientSession.clientSession_processId = processId;
                    clientSession.clientSession_readyToStart = true;
                    clientSession.clientSession_readyToStartDateTime = dateTime.ToUniversalTime();
                    clientSession.clientSession_readyToStartDateTimeOnServer = DateTime.UtcNow;
                    clientSession.testSession.testSession_testSessionStateId = Referential.Guid.TestSessionState.WaitingForStart;

                    z4sEntities.SaveChanges();
                }
            }
        }

        /// <summary>
        /// Persists information of a ClientSession entity on its Started state.
        /// </summary>
        /// <param name="clientSessionId">Unique identifier of the ClientSession.</param>
        /// <param name="dateTime">Date and time when the ClientSession is started.</param>
        public void ClientSessionStarted( Guid clientSessionId, DateTime dateTime )
        {
            using(Zen4SyncRepositoryEntities z4sEntities = GetContext())
            {
                clientSession clientSession = z4sEntities.clientSession.Where
                    ( cs => cs.clientSession_id == clientSessionId ).SingleOrDefault();

                if ( clientSession != null )
                {
                    clientSession.clientSession_startDateTime = dateTime.ToUniversalTime();
                    clientSession.clientSession_startDateTimeOnServer = DateTime.UtcNow;
                    clientSession.testSession.testSession_testSessionStateId = Referential.Guid.TestSessionState.InProgress;

                    z4sEntities.SaveChanges();
                }
            }
        }

        /// <summary>
        /// Persists information of a ClientSession entity when it is enabled to start.
        /// </summary>
        /// <param name="clientSessionId">Unique identifier of the ClientSession.</param>
        /// <param name="error">Error message.</param>
        public void ClientSessionUnableToStart( Guid clientSessionId, string error )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                clientSession clientSession = z4sEntities.clientSession.Where
                    ( cs => cs.clientSession_id == clientSessionId ).SingleOrDefault();

                if ( clientSession != null )
                {
                    clientSession.clientSession_error = error;

                    z4sEntities.SaveChanges();
                }
            }
        }

        /// <summary>
        /// Persists information of a ClientSession entity on its Ended state.
        /// </summary>
        /// <param name="clientSessionId">Unique identifier of the ClientSession.</param>
        /// <param name="dateTime">Date and time when the ClientSession ended its work.</param>
        public void ClientSessionEndedSuccessfully( Guid clientSessionId, DateTime dateTime )
        {
            using(Zen4SyncRepositoryEntities z4sEntities = GetContext())
            {
                clientSession clientSession = z4sEntities.clientSession.Where
                    ( cs => cs.clientSession_id == clientSessionId ).SingleOrDefault();

                if ( clientSession != null )
                {
                    clientSession.clientSession_endDateTime = dateTime.ToUniversalTime();
                    clientSession.clientSession_endDateTimeOnServer = DateTime.UtcNow;
                    z4sEntities.SaveChanges();
                    
                    if ( IsTestSessionOver(clientSession.testSession) )
                    {
                        clientSession.testSession.testSession_testSessionStateId = Referential.Guid.TestSessionState.Completed;
                        z4sEntities.SaveChanges();
                    }                    
                }
            }
        }

        /// <summary>
        /// Persists information of a ClientSession entity on its EndedWitheError state.
        /// </summary>
        /// <param name="clientSessionId">Unique identifier of the ClientSession.</param>
        /// <param name="dateTime">Date and time when the ClientSession ended its work with an error.</param>
        /// <param name="exceptionMessage">Error message.</param>
        public void ClientSessionEndedWithError( Guid clientSessionId, DateTime dateTime, string exceptionMessage )
        {
            using(Zen4SyncRepositoryEntities z4sEntities = GetContext())
            {
                clientSession clientSession = z4sEntities.clientSession.Where
                    ( cs => cs.clientSession_id == clientSessionId ).SingleOrDefault();

                if ( clientSession != null )
                {
                    clientSession.clientSession_endDateTime = dateTime.ToUniversalTime();
                    clientSession.clientSession_error = exceptionMessage;
                    clientSession.clientSession_endDateTimeOnServer = DateTime.UtcNow;

                    z4sEntities.SaveChanges();
                    
                    if ( IsTestSessionOver(clientSession.testSession) )
                    {
                        clientSession.testSession.testSession_testSessionStateId = Referential.Guid.TestSessionState.Completed;
                        z4sEntities.SaveChanges();
                    }
                }
            }
        }

        /// <summary>
        /// Creates the activityHistory entity associated with an Activity.
        /// Persists information on the Started state of the Activity by updating the associated activityHistory entity.
        /// </summary>
        /// <param name="clientSessionId">Unique identifier of the ClientSession.</param>
        /// <param name="activityId">Unique identifier of the activity.</param>
        /// <param name="dateTime">Date and time when the activity starts.</param>
        public void ActivityStarted( Guid clientSessionId, Guid activityId, DateTime dateTime )
        {
            using(Zen4SyncRepositoryEntities z4sEntitites = GetContext())
            {
                activityHistory activityHistory = new activityHistory();

                activityHistory.activityHistory_id = Guid.NewGuid();
                activityHistory.activityHistory_clientSessionId = clientSessionId;
                activityHistory.activityHistory_activityId = activityId;
                activityHistory.activityHistory_startDateTime = dateTime.ToUniversalTime();
                activityHistory.activityHistory_startDateTimeOnServer = DateTime.UtcNow;

                z4sEntitites.activityHistory.AddObject( activityHistory );
                z4sEntitites.SaveChanges();
            }
        }

        /// <summary>
        /// Persists information on the Ended state of an Activity by updating the associated activityHistory entity.
        /// </summary>
        /// <param name="clientSessionId">Unique identifier of the ClientSession.</param>
        /// <param name="activityId">Unique identifier of the activity.</param>
        /// <param name="dateTime">Date and time when the activity ends.</param>
        public void ActivityEndedSuccessfully( Guid clientSessionId, Guid activityId, DateTime dateTime )
        {
            using(Zen4SyncRepositoryEntities z4sEntitites = GetContext())
            {
                activityHistory activityHistory = z4sEntitites.activityHistory.Where
                    ( ah => ah.activityHistory_clientSessionId == clientSessionId &&
                           ah.activityHistory_activityId == activityId ).SingleOrDefault();

                if ( activityHistory != null )
                {
                    activityHistory.activityHistory_endDateTime = dateTime.ToUniversalTime();
                    activityHistory.activityHistory_endDateTimeOnServer = DateTime.UtcNow;

                    z4sEntitites.SaveChanges();
                }
            }
        }

        /// <summary>
        /// Persists information on the EndedWithError state of an Activity by updating the associated activityHistory entity.
        /// </summary>
        /// <param name="clientSessionId">Unique identifier of the ClientSession.</param>
        /// <param name="activityId">Unique identifier of the activity.</param>
        /// <param name="dateTime">Date and time when the activity ends with an error.</param>
        /// <param name="exceptionMessage">Error message.</param>
        public void ActivityEndedWithError( Guid clientSessionId, Guid activityId, DateTime dateTime, string exceptionMessage )
        {
            using(Zen4SyncRepositoryEntities z4sEntities = GetContext())
            {
                activityHistory activityHistory = z4sEntities.activityHistory.Where
                    ( ah => ah.activityHistory_clientSessionId == clientSessionId &&
                           ah.activityHistory_activityId == activityId ).SingleOrDefault();

                if ( activityHistory != null )
                {
                    activityHistory.activityHistory_endDateTime = dateTime.ToUniversalTime();
                    activityHistory.activityHistory_error = exceptionMessage;
                    activityHistory.activityHistory_endDateTimeOnServer = DateTime.UtcNow;

                    z4sEntities.SaveChanges();
                }
            }
        }

        /// <summary>
        /// Creates and persists the mefExecutionHistory entity associated to an Activity.
        /// </summary>
        /// <param name="clientSessionId">Unique identifier of the ClientSession.</param>
        /// <param name="activityId">Unique identifier of the activity.</param>
        /// <param name="metadata">Metadata of the activity.</param>
        public void LogMefExecution( Guid clientSessionId, Guid activityId, string metadata )
        {
            using(Zen4SyncRepositoryEntities z4sEntities = GetContext())
            {
                activityHistory activityHistory = z4sEntities.activityHistory.Where
                    ( ah => ah.activityHistory_clientSessionId == clientSessionId &&
                           ah.activityHistory_activityId == activityId ).SingleOrDefault();

                if ( activityHistory != null )
                {
                    mefExecutionHistory mefExecutionHistory = new mefExecutionHistory();
                    mefExecutionHistory.mefExecutionHistory_id = Guid.NewGuid();
                    mefExecutionHistory.mefExecutionHistory_activityHistoryId = activityHistory.activityHistory_id;
                    mefExecutionHistory.mefExecutionHistory_metadata = metadata;

                    z4sEntities.mefExecutionHistory.AddObject( mefExecutionHistory );
                    z4sEntities.SaveChanges();
                }
            }
        }

        /// <summary>
        /// Creates and persists the sqlceExecutionHistory entity associated to an Activity.
        /// </summary>
        /// <param name="clientSessionId">Unique identifier of the ClientSession.</param>
        /// <param name="activityId">Unique identifier of the activity.</param>
        /// <param name="sqlceExecutionContext">Execution context of the sqlceExecution.</param>
        public void LogSqlCEexecution( Guid clientSessionId, Guid activityId, sqlceExecutionContext sqlceExecutionContext )
        {
            using(Zen4SyncRepositoryEntities z4sEntities = GetContext())
            {
                activityHistory activityHistory = z4sEntities.activityHistory.Where
                    ( ah => ah.activityHistory_clientSessionId == clientSessionId &&
                           ah.activityHistory_activityId == activityId ).SingleOrDefault();

                if ( activityHistory != null )
                {

                    foreach ( sqlceExecutionParameter sqlceExecutionParameter in sqlceExecutionContext.sqlceExecutionParameter )
                    {
                        sqlceExecutionHistory sqlceExecutionHistory = new sqlceExecutionHistory();
                        sqlceExecutionHistory.sqlceExecutionHistory_id = Guid.NewGuid();
                        sqlceExecutionHistory.sqlceExecutionHistory_activityHistoryId = activityHistory.activityHistory_id;
                        sqlceExecutionHistory.sqlceExecutionHistory_parameterName = sqlceExecutionParameter.sqlceExecutionParameter_name;
                        sqlceExecutionHistory.sqlceExecutionHistory_parameterValue = sqlceExecutionParameter.sqlceExecutionParameter_value;
                        z4sEntities.sqlceExecutionHistory.AddObject( sqlceExecutionHistory );
                    }
                    z4sEntities.SaveChanges();
                }
            }
        }

        /// <summary>
        /// Creates and persists the sqlServerExecutionHistory entity associated to an Activity.
        /// </summary>
        /// <param name="clientSessionId">Unique identifier of the ClientSession.</param>
        /// <param name="activityId">Unique identifier of the activity.</param>
        /// <param name="sqlServerExecutionContext">Execution context of the sqlServerExecution.</param>
        public void LogSQLServerExecution( Guid clientSessionId, Guid activityId, sqlServerExecutionContext sqlServerExecutionContext )
        {
            using(Zen4SyncRepositoryEntities z4sEntities = GetContext())
            {
                activityHistory activityHistory = z4sEntities.activityHistory.Where
                    ( ah => ah.activityHistory_clientSessionId == clientSessionId &&
                           ah.activityHistory_activityId == activityId ).SingleOrDefault();
                if ( activityHistory != null )
                {
                    foreach ( sqlServerExecutionParameter sqlserverExecutionParameter in sqlServerExecutionContext.sqlServerExecutionParameter )
                    {
                        sqlServerExecutionHistory sqlServerExecutionHistory = new sqlServerExecutionHistory();
                        sqlServerExecutionHistory.sqlServerExecutionHistory_id = Guid.NewGuid();
                        sqlServerExecutionHistory.sqlServerExecutionHistory_activityHistoryId = activityHistory.activityHistory_id;
                        sqlServerExecutionHistory.sqlServerExecutionHistory_parameterName = sqlserverExecutionParameter.sqlServerExecutionParameter_name;
                        sqlServerExecutionHistory.sqlServerExecutionHistory_parameterValue = sqlserverExecutionParameter.sqlServerExecutionParameter_value;
                        z4sEntities.sqlServerExecutionHistory.AddObject( sqlServerExecutionHistory );
                    }
                    z4sEntities.SaveChanges();
                }
            }
        }

        /// <summary>
        /// Creates and persists the sqlceBackupHistory entity associated to an Activity.
        /// </summary>
        /// <param name="clientSessionId">Unique identifier of the ClientSession.</param>
        /// <param name="activityId">Unique identifier of the activity.</param>
        /// <param name="sqlCeDatabase">The sqlceDatabase file as a byte array.</param>
        public void LogBackupActivity( Guid clientSessionId, Guid activityId, byte[] sqlCeDatabase )
        {
            using(Zen4SyncRepositoryEntities z4sEntities = GetContext())
            {
                activityHistory activityHistory = z4sEntities.activityHistory.Where
                    ( ah => ah.activityHistory_clientSessionId == clientSessionId &&
                           ah.activityHistory_activityId == activityId ).SingleOrDefault();

                if ( activityHistory != null )
                {
                    sqlceBackupHistory sqlceBackupHistory = new sqlceBackupHistory();
                    sqlceBackupHistory.sqlceBackupHistory_id = Guid.NewGuid();
                    sqlceBackupHistory.sqlceBackupHistory_activityHistoryId = activityHistory.activityHistory_id;
                    sqlceBackupHistory.sqlceBackupHistory_sqlCeDatabase = sqlCeDatabase;

                    z4sEntities.sqlceBackupHistory.AddObject( sqlceBackupHistory );
                    z4sEntities.SaveChanges();
                }
            }
        }
   
        /// <summary>
        /// Checks if the TestSession is over (i.e. all clients have an end date time)
        /// </summary>
        /// <param name="testSession">Unique identifier of the TestSession</param>
        /// <returns>If the TestSession is over</returns>
        private bool IsTestSessionOver(testSession testSession)
        {
            return (testSession.clientSession.Where( c => c.clientSession_endDateTime == null ).ToList().Count == 0);
        }
    }
}
